#include "tgaimage.h"

#include "gtest/gtest.h"
#include <iostream>
#include <filesystem>
#include <memory.h>

namespace {

using raster::TGAColor;
using raster::TGAImage;
namespace fs = std::filesystem;

class TGAColorTest: public testing::Test {
protected:
    void SetUp() override {
        c1 = TGAColor(1, 2, 3, 4);
    }
    void TearDown() override {

    }

    TGAColor c1;
};

TEST_F(TGAColorTest, Constructor) {
    TGAColor color1;
    EXPECT_EQ(color1.a, 0);
    EXPECT_EQ(color1.r, 0);
    EXPECT_EQ(color1.g, 0);
    EXPECT_EQ(color1.b, 0);
    EXPECT_EQ(color1.bytespp, 1);

    TGAColor color2(2);
    EXPECT_EQ(color2.a, 2);
    EXPECT_EQ(color2.r, 2);
    EXPECT_EQ(color2.g, 2);
    EXPECT_EQ(color2.b, 2);
    EXPECT_EQ(color2.bytespp, 1);

    TGAColor color3(1, 2, 3);
    EXPECT_EQ(color3.a, 255);
    EXPECT_EQ(color3.r, 1);
    EXPECT_EQ(color3.g, 2);
    EXPECT_EQ(color3.b, 3);
    EXPECT_EQ(color3.bytespp, 3);

    TGAColor color4(1, 2, 3, 4);
    EXPECT_EQ(color4.a, 4);
    EXPECT_EQ(color4.r, 1);
    EXPECT_EQ(color4.g, 2);
    EXPECT_EQ(color4.b, 3);
    EXPECT_EQ(color4.bytespp, 4);

    uint8_t a[] = {1, 2};
    TGAColor color5(a, sizeof(a)/sizeof(a[0]));
    EXPECT_EQ(color5.a, 0);
    EXPECT_EQ(color5.r, 0);
    EXPECT_EQ(color5.g, 2);
    EXPECT_EQ(color5.b, 1);
    EXPECT_EQ(color5.bytespp, 2);

    uint8_t b[] = {1, 2, 3, 4};
    TGAColor color6(b, sizeof(b)/sizeof(b[0]));
    EXPECT_EQ(color6.a, 4);
    EXPECT_EQ(color6.r, 3);
    EXPECT_EQ(color6.g, 2);
    EXPECT_EQ(color6.b, 1);
    EXPECT_EQ(color6.bytespp, 4);
}

TEST_F(TGAColorTest, Accessor) {
    // rgba=1234, array sequence: bgra
    EXPECT_EQ(c1[0], 3);
    EXPECT_EQ(c1[1], 2);
    EXPECT_EQ(c1[2], 1);
    EXPECT_EQ(c1[3], 4);
}

TEST_F(TGAColorTest, NumMultiply) {
    // rgba=1234, array sequence: bgra
    auto c = c1 * 0.5f;
    EXPECT_EQ(c[0], 1);
    EXPECT_EQ(c[1], 1);
    EXPECT_EQ(c[2], 0);
    EXPECT_EQ(c[3], 2);
}

class TGAImageTest: public testing::Test {
protected:
    void SetUp() override {
        image = std::make_unique<TGAImage>(600, 600, 4);

        // ensure existence of the target output directory
        if (!fs::exists(outPath)) {
            try {
                fs::create_directories(outPath);
            } catch(const fs::filesystem_error &e) {
                std::cerr << "reason: " << e.what() << std::endl;
            }
        }

        auto path = fs::current_path();
        std::cout << "current path: " << path << std::endl;

        std::cout << "basePath: " << basePath << std::endl;
        std::cout << "inPath: " << inPath << std::endl;
        std::cout << "outPath: " << outPath << std::endl;
    }

    void TearDown() override {

    }

    std::unique_ptr<TGAImage> image;
    fs::path basePath = PROJECT_ROOT_DIR;
    fs::path inPath = basePath.lexically_normal() / "obj";
    fs::path outPath = basePath.lexically_normal() / "build" / "obj";
    // TGAImage image;
};

TEST_F(TGAImageTest, Constructor) {
    fs::path tgaPath = inPath / "floor_diffuse.tga";
    fs::path tgaAbsolutePath = fs::absolute(tgaPath); // convert relative path to absolute path
    std::cout << "Relative path: " << tgaPath << std::endl;
    std::cout << "Absolute path: " << tgaAbsolutePath << std::endl;
}

TEST_F(TGAImageTest, ReadTgaFile) {
    fs::path tgaPath = inPath / "red.tga";
    bool res = image->readTgaFile(tgaPath.string().c_str());
    EXPECT_TRUE(res);

    EXPECT_EQ(image->width(), 600);
    EXPECT_EQ(image->height(), 600);
    EXPECT_EQ(image->bytespp(), 4);
    EXPECT_EQ(image->version(), 2);
}

TEST_F(TGAImageTest, WriteTgaFile) {
    fs::path tgaPath;
    int width = 600, height = 600, bpp = 4;
    TGAImage tgaImage(width, height, bpp);

    // black image
    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            tgaImage.set(i, j, raster::kBlackColor);
        }
    }
    tgaPath = outPath / "black.tga";
    tgaImage.writeTgaFile(tgaPath.string().c_str());

    // white image
    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            tgaImage.set(i, j, raster::kWhiteColor);
        }
    }
    tgaPath = outPath / "white.tga";
    tgaImage.writeTgaFile(tgaPath.string().c_str());

    // red image
    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            tgaImage.set(i, j, raster::kRedColor);
        }
    }
    tgaPath = outPath / "red.tga";
    tgaImage.writeTgaFile(tgaPath.string().c_str());

    // green image
    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            tgaImage.set(i, j, raster::kGreenColor);
        }
    }
    tgaPath = outPath / "green.tga";
    tgaImage.writeTgaFile(tgaPath.string().c_str());

    // blue image
    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            tgaImage.set(i, j, raster::kBlueColor);
        }
    }
    tgaPath = outPath / "blue.tga";
    tgaImage.writeTgaFile(tgaPath.string().c_str());
}

}
